#include "tcpmgr.h"
#include <QAbstractSocket>
#include "../usermgr.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <qfileinfo.h>
#include "file_upload.pb.h"
#include "../ConfigMgr.h"

TcpMgr::TcpMgr():_host(""),_port(),_b_recv_pending(false),_message_id(0),_message_len(0)
{
    registerMetaType();
    //连接发送信号用来发送数据
    QObject::connect(this, &TcpMgr::sig_send_data, this, &TcpMgr::slot_send_data);//裸接口
    QObject::connect(this, &TcpMgr::sig_loginRequest, this, &TcpMgr::slot_loginRequest);//登录请求接口
    QObject::connect(this, &TcpMgr::sig_sendUploadRequest, this, &TcpMgr::slot_sendUploadRequest);//上传备份请求接口
    QObject::connect(this, &TcpMgr::sig_sendDownloadRequest, this, &TcpMgr::slot_sendDownloadRequest);//下载请求接口


    //注册消息
    initHandlers();
}

TcpMgr::~TcpMgr(){
    qDebug()<<"TcpMgr析构";
    if (_socket) {
        _socket->disconnectFromHost();
        _socket->deleteLater(); // 安全删除
    }
}
void TcpMgr::initHandlers()
{
    //auto self = shared_from_this();
    //用户登录资源服务器回包:
    _handlers.try_emplace(ID_RES_LOGIN_RSP, [this](ReqId id, int len, QByteArray data){
        Q_UNUSED(len);
        qDebug()<< "handle id is "<< id ;
        // 将QByteArray转换为QJsonDocument
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

        // 检查转换是否成功
        if(jsonDoc.isNull()){
            qDebug() << "Failed to create QJsonDocument.";
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();
        qDebug()<< "data jsonobj is " << jsonObj ;

        if(!jsonObj.contains("error")){
            int err = ErrorCodes::Error_Json;
            qDebug() << "Login Failed, err is Json Parse Err" << err ;
            emit sig_login_failed(err);
            return;
        }

        int err = jsonObj["error"].toInt();
        if(err != ErrorCodes::SUCCESS){
            qDebug() << "Login Failed, err is " << err ;
            emit sig_login_failed(err);
            return;
        }

        //登陆成功！切换页面以及设置用户信息
        auto uid = jsonObj["uid"].toInt();
        auto email = jsonObj["email"].toString();
        auto token = jsonObj["token"].toString();

        UserMgr::GetInstance()->setuid(uid);
        UserMgr::GetInstance()->setemail(email);
        UserMgr::GetInstance()->settoken(token);

        emit sig_swich_mainwindow();
    });
    //用户备份文件回包:
    _handlers.try_emplace(ID_FILE_UPLOAD_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        // return;
        file_upload::FileUploadRsp rsp;
        if (!rsp.ParseFromArray(data.data(), len)) {
            qDebug() << "解析FileUploadRsp失败";
            return;
        }

        if (rsp.error_code() != 0) {
            qDebug() << "切片上传失败，错误码：" << rsp.error_code()
                     << "，seq：" << rsp.seq()
                     << "，file_hash：" << QString::fromStdString(rsp.file_hash());
            // 此处可添加切片重试逻辑（记录失败的seq，定时重发）
            return;
        }

        // 验证上下文
        QString fileHash = QString::fromStdString(rsp.file_hash());
        // 使用互斥锁保护上下文操作
        std::lock_guard<std::mutex> lock(_uploadMutex);

        // 验证上下文
        auto it = _uploadContext.find(fileHash);
        if (it == _uploadContext.end())  {
            qDebug() << "未找到上传上下文，file_hash：" << fileHash;
            return;
        }

        UploadContext &ctx = it->second;
        // 更新已完成切片序号
        ctx.completedSeq  = rsp.seq();
        qDebug() << "切片接收成功：" << fileHash
                 << "，进度：" << ctx.completedSeq  << "/" << ctx.totalSeq;

        // 判断是否所有切片都已完成
        if (ctx.completedSeq  == ctx.totalSeq)  {
            // 最终完成：更新fileId并触发后续流程
            ctx.fileInfo.fileId  = rsp.file_id();
            ctx.isCompleted  = true;

            // 移除上下文并通知UI
            UploadContext completedCtx = std::move(ctx);
            _uploadContext.erase(it);

            HistoryItemInfo info = completedCtx.fileInfo;
            info.isUploaded  = true;

            emit sig_uploadFinished(info); // 更新历史记录状态
            emit sig_addBackupRecord(completedCtx.fileInfo);  // 添加到备份表

            qDebug() << "文件上传完成，file_id：" << completedCtx.fileInfo.fileId;
        }
    });

    //用户下载文件回包回调:
    _handlers.try_emplace(ID_FILE_DOWNLOAD_RSP, [this](ReqId id, int len, QByteArray data) {
        file_download::FileDownloadRsp rsp;
        if (!rsp.ParseFromArray(data.data(), data.size())) {
            qDebug() << "解析FileDownloadRsp失败";
            return;
        }

        // 错误处理
        if (rsp.error_code() != 0) {
            qDebug() << "下载错误，文件ID：" << rsp.file_id()
            << "，错误码：" << rsp.error_code();
            _downloadContext.erase(rsp.file_id());
            emit sig_downloadFinished(rsp.file_id(), false);
            return;
        }

        // 使用互斥锁保护上下文操作
        std::lock_guard<std::mutex> lock(_downloadMutex);

        // 获取或创建下载上下文
        auto it = _downloadContext.find(rsp.file_id());
        if (it == _downloadContext.end())  {
            initializeDownloadContext(rsp);
            it = _downloadContext.find(rsp.file_id());
            if (it == _downloadContext.end())  {
                qDebug() << "无法初始化下载上下文，文件ID：" << rsp.file_id();
                emit sig_downloadFinished(rsp.file_id(),  false);
                return;
            }
        }
        DownloadContext& ctx = it->second;

        // 处理数据块
        if (rsp.chunk_data().size()  > 0) {
            processChunkData(ctx, rsp);
        }

        // 最终包处理
        if (rsp.is_last_chunk())  {
            finalizeDownload(ctx, rsp);
            _downloadContext.erase(it);
        }
    });

    //用户请求分页备份信息回包回调:
    _handlers.try_emplace(ID_BACKUP_INFO_RSP, [this](ReqId id, int len, QByteArray data) {
        Q_UNUSED(len);
        qDebug() << "handle id is " << id << " data is " << data;

        emit sig_getBackupInfoResponse(data); //转发给备份页面处理数据
    });
}

void TcpMgr::handleMsg(ReqId id, int len, QByteArray data)
{
    auto find_iter = _handlers.find(id);
    if(find_iter == _handlers.end()){
        qDebug()<< "not found id ["<< id << "] to handle";
        return ;
    }

    find_iter->second(id,len,data);
}

void TcpMgr::registerMetaType()
{
    qRegisterMetaType<ServerInfo>("ServerInfo");
    qRegisterMetaType<FileInfo>("FileInfo");
    qRegisterMetaType<ReqId>("ReqId");
}

void TcpMgr::initializeDownloadContext(const file_download::FileDownloadRsp &rsp) {
    DownloadContext ctx;

    // 1. 设置保存路径
    QString saveDir = QString::fromStdString(reinterpret_cast<const char*>(ConfigMgr::Inst().GetFileOutPath().u8string().c_str()));
    QString fileName = QString::fromUtf8(rsp.logical_name().data(),
                                         rsp.logical_name().size());
    ctx.savePath  = QString("%1/%2").arg(saveDir, fileName);

    // 2. 创建文件并打开
    if (!ctx.createOutputFile(ctx.savePath))  {
        qDebug() << "无法创建文件：" << ctx.savePath;
        emit sig_downloadFinished(rsp.file_id(),  false);
        return;
    }

    // 3. 初始化上下文数据
    ctx.totalSize  = rsp.total_size();
    if (!rsp.sha256().empty())  {
        ctx.expectedSha256  = QString::fromStdString(rsp.sha256());
    }

    // 使用互斥锁保护上下文操作
    std::lock_guard<std::mutex> lock(_downloadMutex);
    _downloadContext[rsp.file_id()] = std::move(ctx);
}

void TcpMgr::processChunkData(DownloadContext &ctx, const file_download::FileDownloadRsp &rsp) {
    // 第一次收到数据时记录文件名等信息
    if (ctx.isFirstChunk)  {
        ctx.fileInfo.logicalName  = QString::fromStdString(rsp.logical_name());
        ctx.fileInfo.fileSize  = rsp.total_size();
        ctx.isFirstChunk  = false;
    }

    // 写入数据
    qint64 bytesWritten = ctx.outputFile->write(
        rsp.chunk_data().data(),
        rsp.chunk_data().size()
        );

    if (bytesWritten != rsp.chunk_data().size())  {
        qDebug() << "写入文件失败，文件：" << ctx.savePath;
        ctx.outputFile->close();
        ctx.outputFile->remove();
        {
            std::lock_guard<std::mutex> lock(_downloadMutex);
            _downloadContext.erase(rsp.file_id());
        }
        emit sig_downloadFinished(rsp.file_id(),  false);
        return;
    }

    // 更新接收进度
    ctx.receivedBytes  += bytesWritten;
    emit sig_downloadProgress(rsp.file_id(),  ctx.receivedBytes,  ctx.totalSize);
}

QString TcpMgr::calculateFileSha256(const QString &filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开文件用于SHA256计算:" << filePath;
        return QString();
    }

    QCryptographicHash hash(QCryptographicHash::Sha256);
    if (hash.addData(&file)) {
        return QString(hash.result().toHex());
    }
    return QString();
}

void TcpMgr::finalizeDownload(DownloadContext &ctx, const file_download::FileDownloadRsp &rsp) {
    ctx.outputFile->close();

    // SHA256校验
    if (!rsp.sha256().empty())  {
        QString expectedSha256 = QString::fromStdString(rsp.sha256());
        QString actualSha256 = calculateFileSha256(ctx.savePath);

        if (actualSha256.isEmpty()  || actualSha256 != expectedSha256) {
            qDebug() << "SHA256校验失败，文件：" << ctx.savePath
                     << "\n期望值：" << expectedSha256
                     << "\n实际值：" << actualSha256;

            QFile::remove(ctx.savePath);
            emit sig_downloadFinished(rsp.file_id(),  false);
            return;
        }
        qDebug() << "SHA256校验通过：" << actualSha256;
    }

    // 更新上下文并通知完成
    ctx.fileInfo.fileId  = rsp.file_id();
    emit sig_downloadFinished(rsp.file_id(),  true);

    qDebug() << "文件下载完成：" << ctx.savePath
             << "，大小：" << ctx.receivedBytes  << "字节";
}

void TcpMgr::initSocket()
{
    _socket = new QTcpSocket(this); // 父对象为this（TcpMgr），确保线程一致
    // 在这里连接_socket的所有信号（原构造函数中的连接移到此处）
    connect(_socket, &QTcpSocket::connected, [&]() {
        qDebug() << "Connected to server!";
        emit sig_con_success(true);
    });
    QObject::connect(_socket, &QTcpSocket::readyRead, [&]() {
        // 当有数据可读时，读取所有数据
        // 读取所有数据并追加到缓冲区
        _buffer.append(_socket->readAll());

        QDataStream stream(&_buffer, QIODevice::ReadOnly);
        stream.setVersion(QDataStream::Qt_5_0);

        forever {
            //先解析头部
            if(!_b_recv_pending){
                // 检查缓冲区中的数据是否足够解析出一个消息头（消息ID + 消息长度）
                if (_buffer.size() < TCP_HEAD_LEN/*static_cast<int>(sizeof(quint16) * 2*/) {
                    return; // 数据不够，等待更多数据
                }

                // 预读取消息ID和消息长度，但不从缓冲区中移除
                stream >> _message_id >> _message_len;

                //将buffer 中的前四个字节移除(此时buffer为纯body)
                _buffer = _buffer.mid(TCP_HEAD_LEN);

                // 输出读取的数据
                qDebug() << "Message ID:" << _message_id << ", Length:" << _message_len;

            }

            //buffer剩余长读是否满足消息体长度，不满足则退出继续等待接受
            if(_buffer.size() < _message_len){
                _b_recv_pending = true;
                return;
            }

            _b_recv_pending = false;
            // 读取消息体
            QByteArray messageBody = _buffer.mid(0, _message_len);
            qDebug() << "receive body msg is " << messageBody ;

            _buffer = _buffer.mid(_message_len);

            handleMsg(ReqId(_message_id),_message_len, messageBody);
        }

    });

    //5.15 之后版本
    QObject::connect(_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), [&](QAbstractSocket::SocketError socketError) {
        Q_UNUSED(socketError)
        qDebug() << "TCP Error:" << _socket->errorString();
    });

    // 处理连接断开
    QObject::connect(_socket, &QTcpSocket::disconnected, [&]() {
        qDebug() << "Disconnected from server.";
    });

    QObject::connect(_socket, &QTcpSocket::bytesWritten, this, [this](qint64 bytes) {
        //更新发送数据
        _bytes_sent += bytes;
        //未发送完整
        if (_bytes_sent < _current_block.size()) {
            //继续发送
            auto data_to_send = _current_block.mid(_bytes_sent);
            _socket->write(data_to_send);
            return;
        }

        //发送完全，则查看队列是否为空
        if (_send_queue.empty()) {
            //队列为空，说明已经将所有数据发送完成，将pending设置为false，这样后续要发送数据时可以继续发送
            _current_block.clear();
            _pending = false;
            _bytes_sent = 0;
            return;
        }

        //队列不为空，则取出队首元素
        _current_block = _send_queue.front();
        _send_queue.pop();
        _bytes_sent = 0;
        _pending = true;
        qint64 w2 = _socket->write(_current_block);
        qDebug() << "[TcpMgr] Dequeued and write() returned" << w2;
    });
}

void TcpMgr::slot_tcp_connect(ServerInfo si)
{
    qDebug()<< "receive tcp connect signal";
    // 尝试连接到服务器
    qDebug() << "Connecting to server...";
    _host = si.Host;
    _port = static_cast<uint16_t>(si.Port.toUInt());
    _socket->connectToHost(si.Host, _port);
}

void TcpMgr::slot_send_data(ReqId reqId, QByteArray dataBytes)
{
    qDebug()<<"receive sig_send_data";
    uint16_t id = reqId;

    // 计算长度
    quint32 len = dataBytes.size();

    // 创建一个QByteArray用于存储要发送的所有数据
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);

    // 设置数据流使用网络字节序
    out.setByteOrder(QDataStream::BigEndian);

    // 写入ID和长度
    out << id << len;

    // 添加字符串数据
    block.append(dataBytes);

    //判断是否正在发送
    if (_pending) {
        //放入队列直接返回，因为目前有数据正在发送
        qDebug()<<"放入队列直接返回，因为目前有数据正在发送";
        _send_queue.push(block);
        return;
    }

    // 没有正在发送，把这包设为“当前块”，重置计数，并写出去
    _current_block = block; // ← 保存当前正在发送的 block
    _bytes_sent = 0; // ← 归零
    _pending = true; // ← 标记正在发送

    // 发送数据
    qint64 written = _socket->write(_current_block);

    qDebug() << "tcp mgr send byte data is" << _current_block
             << ", write() returned" << written;
}

void TcpMgr::slot_loginRequest(const QByteArray &data)
{
    slot_send_data(ReqId::ID_RES_LOGIN, data);
}

void TcpMgr::slot_sendUploadRequest(const QByteArray &data, const FileInfo &info)
{
    // _uploadContext[info.fileHash] = info; // 用file_hash关联
    // slot_send_data(ID_FILE_UPLOAD_REQ, data);
    // 解析请求数据获取切片信息
    file_upload::FileUploadReq req;
    if (!req.ParseFromArray(data.data(), data.size())) {
        qDebug() << "解析FileUploadReq失败";
        return;
    }

    QString fileHash = QString::fromStdString(req.file_hash());
    // 使用互斥锁保护上下文操作
    std::lock_guard<std::mutex> lock(_uploadMutex);

    // 首次发送该文件时，初始化上下文
    if (_uploadContext.find(fileHash)  == _uploadContext.end())  {
        UploadContext ctx;
        ctx.fileInfo  = info;
        ctx.totalSeq  = req.last_seq();
        ctx.completedSeq  = 0;
        ctx.isCompleted  = false;
        _uploadContext[fileHash] = ctx;
    }

    // 发送当前切片
    slot_send_data(ID_FILE_UPLOAD_REQ, data);
}

void TcpMgr::slot_sendDownloadRequest(const QByteArray &data, const FileInfo &info)
{
    // 1. 参数校验
    if (data.isEmpty()  || info.fileId  <= 0) {
        qWarning() << "Invalid download request - fileId:" << info.fileId
                   << "data size:" << data.size();
        emit sig_downloadFinished(info.fileId,  false);
        return;
    }

    // 2. 解析请求数据
    file_download::FileDownloadReq req;
    if (!req.ParseFromArray(data.data(),  data.size()))  {
        qCritical() << "Failed to parse FileDownloadReq for fileId:" << info.fileId;
        emit sig_downloadFinished(info.fileId,  false);
        return;
    }

    // 3. 初始化下载上下文
    {
        std::lock_guard<std::mutex> lock(_downloadMutex);
        if (_downloadContext.find(info.fileId)  == _downloadContext.end())  {
            DownloadContext ctx;
            ctx.fileInfo  = info;
            _downloadContext[info.fileId] = std::move(ctx);

            qDebug() << "Initialized download context for fileId:" << info.fileId
                     << "| Expected name:" << info.logicalName;
        }
    }

    // 4. 发送请求
    slot_send_data(ID_FILE_DOWNLOAD_REQ, data);
}

void TcpMgr::slot_sendGetBackupInfoRequest(const QByteArray &data)
{
    slot_send_data(ID_BACKUP_INFO_REQ, data);
}

TcpThread::TcpThread()
{
    _tcp_thread = new QThread();
    TcpMgr::GetInstance()->moveToThread(_tcp_thread);
    // QObject::connect(_tcp_thread, &QThread::finished, _tcp_thread, &QObject::deleteLater);

    // _tcp_thread->start();
    // 连接线程启动信号到initSocket，确保_socket在新线程中创建
    QObject::connect(_tcp_thread, &QThread::started, TcpMgr::GetInstance().get(), &TcpMgr::initSocket);
    QObject::connect(_tcp_thread, &QThread::finished, _tcp_thread, &QObject::deleteLater);
    _tcp_thread->start();
}

TcpThread::~TcpThread()
{
    _tcp_thread->quit();
}
